/*
 This file 'position' is part of Firebird Integrated Solution 1.0

 Copyright (c) 2015 Lincong

 Contact:  
 Email: lincong1987@gmail.com

 QQ: 159257119

 See Usage at http://www.jplatformx.com/firebird

 Create date: 2015-07-14 04:36
 */


(function ($, undefined) {

	$.ui = $.ui || {};

	var cachedScrollbarWidth,
		max = Math.max,
		abs = Math.abs,
		round = Math.round,
		rhorizontal = /left|center|right/,
		rvertical = /top|center|bottom/,
		roffset = /[\+\-]\d+%?/,
		rposition = /^\w+/,
		rpercent = /%$/,
		_position = $.fn.position;

	function getOffsets(offsets, width, height) {
		return [
			parseInt(offsets[0], 10) * ( rpercent.test(offsets[0]) ? width / 100 : 1 ),
			parseInt(offsets[1], 10) * ( rpercent.test(offsets[1]) ? height / 100 : 1 )
		];
	}

	function parseCss(element, property) {
		return parseInt($.css(element, property), 10) || 0;
	}

	$.position = {
		scrollbarWidth: function () {
			if (cachedScrollbarWidth !== undefined) {
				return cachedScrollbarWidth;
			}
			var w1, w2,
				div = $("<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>"),
				innerDiv = div.children()[0];

			$("body").append(div);
			w1 = innerDiv.offsetWidth;
			div.css("overflow", "scroll");

			w2 = innerDiv.offsetWidth;

			if (w1 === w2) {
				w2 = div[0].clientWidth;
			}

			div.remove();

			return (cachedScrollbarWidth = w1 - w2);
		},
		getScrollInfo: function (within) {
			var overflowX = within.isWindow ? "" : within.element.css("overflow-x"),
				overflowY = within.isWindow ? "" : within.element.css("overflow-y"),
				hasOverflowX = overflowX === "scroll" ||
					( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
				hasOverflowY = overflowY === "scroll" ||
					( overflowY === "auto" && within.height < within.element[0].scrollHeight );
			return {
				width: hasOverflowX ? $.position.scrollbarWidth() : 0,
				height: hasOverflowY ? $.position.scrollbarWidth() : 0
			};
		},
		getWithinInfo: function (element) {
			var withinElement = $(element || window),
				isWindow = $.isWindow(withinElement[0]);
			return {
				element: withinElement,
				isWindow: isWindow,
				offset: withinElement.offset() || {left: 0, top: 0},
				scrollLeft: withinElement.scrollLeft(),
				scrollTop: withinElement.scrollTop(),
				width: isWindow ? withinElement.width() : withinElement.outerWidth(),
				height: isWindow ? withinElement.height() : withinElement.outerHeight()
			};
		}
	};

	$.fn.position = function (options) {
		if (!options || !options.of) {
			return _position.apply(this, arguments);
		}

		// make a copy, we don't want to modify arguments
		options = $.extend({}, options);

		var atOffset, targetWidth, targetHeight, targetOffset, basePosition,
			target = $(options.of),
			within = $.position.getWithinInfo(options.within),
			scrollInfo = $.position.getScrollInfo(within),
			targetElem = target[0],
			collision = ( options.collision || "flip" ).split(" "),
			offsets = {};

		if (targetElem.nodeType === 9) {
			targetWidth = target.width();
			targetHeight = target.height();
			targetOffset = {top: 0, left: 0};
		} else if ($.isWindow(targetElem)) {
			targetWidth = target.width();
			targetHeight = target.height();
			targetOffset = {top: target.scrollTop(), left: target.scrollLeft()};
		} else if (targetElem.preventDefault) {
			// force left top to allow flipping
			options.at = "left top";
			targetWidth = targetHeight = 0;
			targetOffset = {top: targetElem.pageY, left: targetElem.pageX};
		} else {
			targetWidth = target.outerWidth();
			targetHeight = target.outerHeight();
			targetOffset = target.offset();
		}
		// clone to reuse original targetOffset later
		basePosition = $.extend({}, targetOffset);

		// force my and at to have valid horizontal and vertical positions
		// if a value is missing or invalid, it will be converted to center
		$.each(["my", "at"], function () {
			var pos = ( options[this] || "" ).split(" "),
				horizontalOffset,
				verticalOffset;

			if (pos.length === 1) {
				pos = rhorizontal.test(pos[0]) ?
					pos.concat(["center"]) :
					rvertical.test(pos[0]) ?
						["center"].concat(pos) :
						["center", "center"];
			}
			pos[0] = rhorizontal.test(pos[0]) ? pos[0] : "center";
			pos[1] = rvertical.test(pos[1]) ? pos[1] : "center";

			// calculate offsets
			horizontalOffset = roffset.exec(pos[0]);
			verticalOffset = roffset.exec(pos[1]);
			offsets[this] = [
				horizontalOffset ? horizontalOffset[0] : 0,
				verticalOffset ? verticalOffset[0] : 0
			];

			// reduce to just the positions without the offsets
			options[this] = [
				rposition.exec(pos[0])[0],
				rposition.exec(pos[1])[0]
			];
		});

		// normalize collision option
		if (collision.length === 1) {
			collision[1] = collision[0];
		}

		if (options.at[0] === "right") {
			basePosition.left += targetWidth;
		} else if (options.at[0] === "center") {
			basePosition.left += targetWidth / 2;
		}

		if (options.at[1] === "bottom") {
			basePosition.top += targetHeight;
		} else if (options.at[1] === "center") {
			basePosition.top += targetHeight / 2;
		}

		atOffset = getOffsets(offsets.at, targetWidth, targetHeight);
		basePosition.left += atOffset[0];
		basePosition.top += atOffset[1];

		return this.each(function () {
			var collisionPosition, using,
				elem = $(this),
				elemWidth = elem.outerWidth(),
				elemHeight = elem.outerHeight(),
				marginLeft = parseCss(this, "marginLeft"),
				marginTop = parseCss(this, "marginTop"),
				collisionWidth = elemWidth + marginLeft + parseCss(this, "marginRight") + scrollInfo.width,
				collisionHeight = elemHeight + marginTop + parseCss(this, "marginBottom") + scrollInfo.height,
				position = $.extend({}, basePosition),
				myOffset = getOffsets(offsets.my, elem.outerWidth(), elem.outerHeight());

			if (options.my[0] === "right") {
				position.left -= elemWidth;
			} else if (options.my[0] === "center") {
				position.left -= elemWidth / 2;
			}

			if (options.my[1] === "bottom") {
				position.top -= elemHeight;
			} else if (options.my[1] === "center") {
				position.top -= elemHeight / 2;
			}

			position.left += myOffset[0];
			position.top += myOffset[1];

			// if the browser doesn't support fractions, then round for consistent results
			if (!$.support.offsetFractions) {
				position.left = round(position.left);
				position.top = round(position.top);
			}

			collisionPosition = {
				marginLeft: marginLeft,
				marginTop: marginTop
			};

			$.each(["left", "top"], function (i, dir) {
				if ($.ui.position[collision[i]]) {
					$.ui.position[collision[i]][dir](position, {
						targetWidth: targetWidth,
						targetHeight: targetHeight,
						elemWidth: elemWidth,
						elemHeight: elemHeight,
						collisionPosition: collisionPosition,
						collisionWidth: collisionWidth,
						collisionHeight: collisionHeight,
						offset: [atOffset[0] + myOffset[0], atOffset [1] + myOffset[1]],
						my: options.my,
						at: options.at,
						within: within,
						elem: elem
					});
				}
			});

			if ($.fn.bgiframe) {
				elem.bgiframe();
			}

			if (options.using) {
				// adds feedback as second argument to using callback, if present
				using = function (props) {
					var left = targetOffset.left - position.left,
						right = left + targetWidth - elemWidth,
						top = targetOffset.top - position.top,
						bottom = top + targetHeight - elemHeight,
						feedback = {
							target: {
								element: target,
								left: targetOffset.left,
								top: targetOffset.top,
								width: targetWidth,
								height: targetHeight
							},
							element: {
								element: elem,
								left: position.left,
								top: position.top,
								width: elemWidth,
								height: elemHeight
							},
							horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
							vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
						};
					if (targetWidth < elemWidth && abs(left + right) < targetWidth) {
						feedback.horizontal = "center";
					}
					if (targetHeight < elemHeight && abs(top + bottom) < targetHeight) {
						feedback.vertical = "middle";
					}
					if (max(abs(left), abs(right)) > max(abs(top), abs(bottom))) {
						feedback.important = "horizontal";
					} else {
						feedback.important = "vertical";
					}
					options.using.call(this, props, feedback);
				};
			}

			elem.offset($.extend(position, {using: using}));
		});
	};

	$.ui.position = {
		fit: {
			left: function (position, data) {
				var within = data.within,
					withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
					outerWidth = within.width,
					collisionPosLeft = position.left - data.collisionPosition.marginLeft,
					overLeft = withinOffset - collisionPosLeft,
					overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
					newOverRight;

				// element is wider than within
				if (data.collisionWidth > outerWidth) {
					// element is initially over the left side of within
					if (overLeft > 0 && overRight <= 0) {
						newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
						position.left += overLeft - newOverRight;
						// element is initially over right side of within
					} else if (overRight > 0 && overLeft <= 0) {
						position.left = withinOffset;
						// element is initially over both left and right sides of within
					} else {
						if (overLeft > overRight) {
							position.left = withinOffset + outerWidth - data.collisionWidth;
						} else {
							position.left = withinOffset;
						}
					}
					// too far left -> align with left edge
				} else if (overLeft > 0) {
					position.left += overLeft;
					// too far right -> align with right edge
				} else if (overRight > 0) {
					position.left -= overRight;
					// adjust based on position and margin
				} else {
					position.left = max(position.left - collisionPosLeft, position.left);
				}
			},
			top: function (position, data) {
				var within = data.within,
					withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
					outerHeight = data.within.height,
					collisionPosTop = position.top - data.collisionPosition.marginTop,
					overTop = withinOffset - collisionPosTop,
					overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
					newOverBottom;

				// element is taller than within
				if (data.collisionHeight > outerHeight) {
					// element is initially over the top of within
					if (overTop > 0 && overBottom <= 0) {
						newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
						position.top += overTop - newOverBottom;
						// element is initially over bottom of within
					} else if (overBottom > 0 && overTop <= 0) {
						position.top = withinOffset;
						// element is initially over both top and bottom of within
					} else {
						if (overTop > overBottom) {
							position.top = withinOffset + outerHeight - data.collisionHeight;
						} else {
							position.top = withinOffset;
						}
					}
					// too far up -> align with top
				} else if (overTop > 0) {
					position.top += overTop;
					// too far down -> align with bottom edge
				} else if (overBottom > 0) {
					position.top -= overBottom;
					// adjust based on position and margin
				} else {
					position.top = max(position.top - collisionPosTop, position.top);
				}
			}
		},
		flip: {
			left: function (position, data) {
				var within = data.within,
					withinOffset = within.offset.left + within.scrollLeft,
					outerWidth = within.width,
					offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
					collisionPosLeft = position.left - data.collisionPosition.marginLeft,
					overLeft = collisionPosLeft - offsetLeft,
					overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
					myOffset = data.my[0] === "left" ?
						-data.elemWidth :
						data.my[0] === "right" ?
							data.elemWidth :
							0,
					atOffset = data.at[0] === "left" ?
						data.targetWidth :
						data.at[0] === "right" ?
							-data.targetWidth :
							0,
					offset = -2 * data.offset[0],
					newOverRight,
					newOverLeft;

				if (overLeft < 0) {
					newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
					if (newOverRight < 0 || newOverRight < abs(overLeft)) {
						position.left += myOffset + atOffset + offset;
					}
				}
				else if (overRight > 0) {
					newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
					if (newOverLeft > 0 || abs(newOverLeft) < overRight) {
						position.left += myOffset + atOffset + offset;
					}
				}
			},
			top: function (position, data) {
				var within = data.within,
					withinOffset = within.offset.top + within.scrollTop,
					outerHeight = within.height,
					offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
					collisionPosTop = position.top - data.collisionPosition.marginTop,
					overTop = collisionPosTop - offsetTop,
					overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
					top = data.my[1] === "top",
					myOffset = top ?
						-data.elemHeight :
						data.my[1] === "bottom" ?
							data.elemHeight :
							0,
					atOffset = data.at[1] === "top" ?
						data.targetHeight :
						data.at[1] === "bottom" ?
							-data.targetHeight :
							0,
					offset = -2 * data.offset[1],
					newOverTop,
					newOverBottom;
				if (overTop < 0) {
					newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
					if (( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs(overTop) )) {
						position.top += myOffset + atOffset + offset;
					}
				}
				else if (overBottom > 0) {
					newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
					if (( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs(newOverTop) < overBottom )) {
						position.top += myOffset + atOffset + offset;
					}
				}
			}
		},
		flipfit: {
			left: function () {
				$.ui.position.flip.left.apply(this, arguments);
				$.ui.position.fit.left.apply(this, arguments);
			},
			top: function () {
				$.ui.position.flip.top.apply(this, arguments);
				$.ui.position.fit.top.apply(this, arguments);
			}
		}
	};

// fraction support test
	(function () {
		var testElement, testElementParent, testElementStyle, offsetLeft, i,
			body = document.getElementsByTagName("body")[0],
			div = document.createElement("div");

		//Create a "fake body" for testing based on method used in jQuery.support
		testElement = document.createElement(body ? "div" : "body");
		testElementStyle = {
			visibility: "hidden",
			width: 0,
			height: 0,
			border: 0,
			margin: 0,
			background: "none"
		};
		if (body) {
			$.extend(testElementStyle, {
				position: "absolute",
				left: "-1000px",
				top: "-1000px"
			});
		}
		for (i in testElementStyle) {
			testElement.style[i] = testElementStyle[i];
		}
		testElement.appendChild(div);
		testElementParent = body || document.documentElement;
		testElementParent.insertBefore(testElement, testElementParent.firstChild);

		div.style.cssText = "position: absolute; left: 10.7432222px;";

		offsetLeft = $(div).offset().left;
		$.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;

		testElement.innerHTML = "";
		testElementParent.removeChild(testElement);
	})();

// DEPRECATED
	if ($.uiBackCompat !== false) {
		// offset option
		(function ($) {
			var _position = $.fn.position;
			$.fn.position = function (options) {
				if (!options || !options.offset) {
					return _position.call(this, options);
				}
				var offset = options.offset.split(" "),
					at = options.at.split(" ");
				if (offset.length === 1) {
					offset[1] = offset[0];
				}
				if (/^\d/.test(offset[0])) {
					offset[0] = "+" + offset[0];
				}
				if (/^\d/.test(offset[1])) {
					offset[1] = "+" + offset[1];
				}
				if (at.length === 1) {
					if (/left|center|right/.test(at[0])) {
						at[1] = "center";
					} else {
						at[1] = at[0];
						at[0] = "center";
					}
				}
				return _position.call(this, $.extend(options, {
					at: at[0] + offset[0] + " " + at[1] + offset[1],
					offset: undefined
				}));
			};
		}(jQuery) );
	}

}(jQuery));